/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sd_proj1.monSolution;

import java.util.Random;
import java.util.TreeMap;
import sd_proj1.interfaces.*;

/**
 *
 * @author Valter Vicente
 */
public class MonitorOficina implements IDonaOficina, IArtesao {

	/**
	 *  Quantidade de vezes que a dona repõem matérias primas.
	 *
	 *    @serialField couldSupplyMaterials
	 */
	private final int couldSupplyMaterials = 3;
	/**
	 *  Número de artesãos na oficina
	 *
	 *    @serialField nArtesaos
	 */
	private int nArtesaos;
	/**
	 *  Quantidade de matérias primas disponíveis na oficina.
	 *
	 *    @serialField primeMaterialsAmount
	 */
	private int primeMaterialsAmount;
	/**
	 *  Número de vezes que as matérias primas foram disponibilizadas.
	 *
	 *    @serialField timesSupplied
	 */
	private int timesSupplied = 0;
	/**
	 *  Total de matérias primas que já foram disponibilizadas.
	 *
	 *    @serialField totalPrimeMaterials
	 */
	private int totalPrimeMaterials = 0;
	/**
	 *  Número de produtos terminados presentes na oficina.
	 *
	 *    @serialField finishedProducts
	 */
	private int finishedProducts = 0;
	/**
	 *  Total de produtos que já foram produzidos.
	 *
	 *    @serialField totalProduced
	 */
	private int totalProduced = 0;
	/**
	 *  Quantidade de matérias primas que servirá de alerta para buscar mais
	 *
	 *    @serialField alert
	 */
	private int alert;
	private int[] craftsmanProduced;
	private IntArtesaosFifo general;
	private TreeMap map;
	private Mensagem mlog;

	/**
	 *
	 * @param nArtesaos
	 * @param primeMaterialsAmount
	 * @param alert
	 */
	public MonitorOficina(int nArtesaos, int primeMaterialsAmount, int alert, IntArtesaosFifo general, TreeMap map) {
		this.nArtesaos = nArtesaos;
		this.primeMaterialsAmount = primeMaterialsAmount;
		this.alert = alert;
		this.general = general;
		this.map = map;

		craftsmanProduced = new int[nArtesaos];
		for (int i = 0; i < craftsmanProduced.length; i++) {
			craftsmanProduced[i] = 0;
		}

		if(primeMaterialsAmount < alert || primeMaterialsAmount == 0)
			this.general.primeMaterialsNeeded(0);
	}

	/**
	 * O artesão morre (originada pelo artesão).
	 * @param craftsmanId ID do artesão
	 * @return <li> true, se morre
	 *		<li> false, se não morre
	 */
	public synchronized boolean endOperCraftsman(int craftsmanId) {
		if (primeMaterialsAmount > 0 && timesSupplied <= 3) {
			return false;
		} else {
			nArtesaos--;
			System.out.println("O artesao " + craftsmanId + " KAPUT!");
			if (nArtesaos == 0) {
				general.batchReadyForTransfer(finishedProducts);
				general.setAllCraftsDead(true);

			}
			return true;
		}
	}

	/**
	 * Um artesão vai buscar matérias primas para criar produtos (originada pelo artesão).
	 * @param craftsmanId ID do artesão
	 * @return <li> true, se a quantidade de matérias primas atingir o limite de alerta
	 *		<li> false, se ainda está dentro do limite ou caso tenha sido tirado algum inferior ao limite
	 */
	public synchronized boolean collectMaterials(int craftsmanId) {
		System.out.println("collectMaterials - artesao " + craftsmanId + " FETCHING_PRIME_MATERIALS");

		if (primeMaterialsAmount == 0 && timesSupplied < couldSupplyMaterials) {
			try {
				wait();
			} catch (InterruptedException e) {
			}
		}

		primeMaterialsAmount--;
		mlog = new Mensagem();
		mlog.setStatCraft(Mensagem.craftStat.FTPM, craftsmanProduced[craftsmanId], craftsmanId);
		mlog.setWorkShopStat(primeMaterialsAmount, finishedProducts, timesSupplied, totalPrimeMaterials, totalProduced);
		map.put(Relogio.getInstance().getValue(), mlog);

		if (primeMaterialsAmount == alert && timesSupplied < couldSupplyMaterials) {
			return true;
		}
		return false;
	}

	/**
	 * O artesão volta ao trabalho, indo buscar mais máteria prima (originada pelo artesão).
	 * @param craftsmanId ID do artesão
	 */
	public synchronized void backToWork(int craftsmanId) {
		System.out.println("backToWork - artesao " + craftsmanId + " FETCHING_PRIME_MATERIALS");

		mlog = new Mensagem();
		mlog.setStatCraft(Mensagem.craftStat.FTPM, craftsmanProduced[craftsmanId], craftsmanId);
		map.put(Relogio.getInstance().getValue(), mlog);
	}

	/**
	 * O artesão está pronto a produzir um novo produto (originada pelo artesão).
	 * @param craftsmanId ID do artesão
	 */
	public synchronized void prepareToProduce(int craftsmanId) {
		System.out.println("prepareToProduce - artesao " + craftsmanId + " PRODUCING_A_NEW_PIECE");

		mlog = new Mensagem();
		mlog.setStatCraft(Mensagem.craftStat.PANP, craftsmanProduced[craftsmanId], craftsmanId);
		map.put(Relogio.getInstance().getValue(), mlog);
	}

	/**
	 * O artesão coloca um produto acabado na estante da oficina (originada pelo artesão).
	 * @param craftsmanId ID do artesão
	 * @return A quantidade de produtos acabados presentes na oficina
	 */
	public synchronized int goToStore(int craftsmanId) {
		System.out.println("goToStore - artesao " + craftsmanId + " STORING_IT_FOR_TRANSFER");

		finishedProducts++;
		totalProduced++;

		mlog = new Mensagem();
		mlog.setStatCraft(Mensagem.craftStat.SIFT, ++craftsmanProduced[craftsmanId], craftsmanId);
		mlog.setWorkShopStat(primeMaterialsAmount, finishedProducts, timesSupplied, totalPrimeMaterials, totalProduced);
		map.put(Relogio.getInstance().getValue(), mlog);

		return finishedProducts;
	}

	public synchronized void visitSuppliers() {
		System.out.println("visitSuppliers - dona DELIVERING_PRIME_MATERIALS");

		if (timesSupplied < couldSupplyMaterials) {
			int newMaterials = ((new Random()).nextInt(100) + 1);
			primeMaterialsAmount += newMaterials;
			timesSupplied++;
			totalPrimeMaterials += newMaterials;

			mlog = new Mensagem();
			mlog.setEntrepStat(Mensagem.eStat.DLPM);
			mlog.setShopDoorStat(Mensagem.storeStat.SPCL);
			mlog.setShopStat(-1, -1, '0', 'F');
			mlog.setWorkShopStat(primeMaterialsAmount, finishedProducts, timesSupplied, totalPrimeMaterials, totalProduced);
			map.put(Relogio.getInstance().getValue(), mlog);
		}

		notifyAll();
	}

	/**
	 * TODO Atencao.....NA OFICINA???
	 */
	public synchronized void goToWorkshop() {
		System.out.println("goToWorkshop - dona COLLECTING_A_BATCH_OF_PRODUCTS");

		general.setnPecasTransporte(finishedProducts);
		finishedProducts = 0;

		mlog = new Mensagem();
		mlog.setEntrepStat(Mensagem.eStat.CBOP);
		mlog.setShopDoorStat(Mensagem.storeStat.SPCL);
		mlog.setShopStat(-1, -1, 'F', '0');
		mlog.setWorkShopStat(primeMaterialsAmount, finishedProducts, timesSupplied, totalPrimeMaterials, totalProduced);
		map.put(Relogio.getInstance().getValue(), mlog);
	}
}
